package work.linruchang.util.bean.wrapper;


import work.linruchang.util.bean.wrapper.db.SqlColumnInfo;
import work.linruchang.util.bean.wrapper.impl.HavingWrapperImpl;
import work.linruchang.util.bean.wrapper.impl.OnWrapperImpl;

import java.util.Set;

/**
 * 查询SQL构建器
 * 构建使用请参考{cn.eshore.common.db.wrapper.QueryWrapperImplTest}
 * @param <FirstTable>
 */
public interface QueryWrapper<FirstTable> extends WhereWrapper<FirstTable, QueryWrapper<FirstTable>> {

    Set<SqlColumnInfo> getSelectColumnInfos();

    /**
     * 自动连表
     * 必须在主表定义需要被连的表以及字段{ TableJoin}
     *
     * @param tableClazzs 与主表想连的表
     * @return
     */
    QueryWrapper<FirstTable> autoJoin(Class... tableClazzs);

    /**
     * 需要select的字段 == 计算记录数
     * 一旦触发即使select其他字段也会直接忽略，所以此方法仅仅只用来统计行数而已
     *
     * @return
     */
    QueryWrapper<FirstTable> count();

    /**
     * 需要select的字段 == 字段结果集是key
     * <p>
     * 其实内部调的依然还是{ QueryWrapper#select(Class, String...)}
     *
     * @param dbFieldName      主表的列名
     * @param dbFieldNameAlias 主表的{dbFieldName}列的别名 == 用于结果集
     * @return
     */
    QueryWrapper<FirstTable> selectAlias(String dbFieldName, String dbFieldNameAlias);

    /**
     * 需要select的字段 == 字段结果集是key
     * <p>
     * 其实内部调的依然还是{ QueryWrapper#select(Class, String...)}
     *
     * @param tableClazz       列名{dbFieldName}所属的表
     * @param dbFieldName      表{tableClazz}的列名
     * @param dbFieldNameAlias 表{tableClazz}的{dbFieldName}列的别名 == 用于结果集
     * @return
     */
    QueryWrapper<FirstTable> selectAlias(Class tableClazz, String dbFieldName, String dbFieldNameAlias);

    /**
     * 需要select的字段
     * <p>
     * select("字段名") ==》 主表的字段名的别名即本身  => 表别名.字段名
     * select(主表, "字段名a") select(副表, "字段名a") ==》 非主表的字段全部需要起别名格式 => 表别名.字段名 AS '表别名.字段名'
     * select("字段名 AS 字段名别名")  => 表别名.字段名 AS '字段名别名'
     * select("字段名 AS '字段名别名'")  => 表别名.字段名 AS '字段名别名'
     *
     * @param dbFieldNames 字段名 == 默认全是主表的字段
     *                     如    name => 表chaiji_status => cs_8d053.account
     * @return
     */
    QueryWrapper<FirstTable> select(String... dbFieldNames);

    /**
     * 需要select的字段 == 支持表别名SQL
     *
     * select("字段名") ==》 主表的字段名的别名即本身  => 表别名.字段名
     * select(tableClazz,"*") ==》 表{tableClazz}的*
     * select("*") ==》 主表的*
     * select(主表, "字段名a") select(副表, "字段名a") ==》 非主表的字段全部需要起别名格式 => 表别名.字段名 AS '表别名.字段名'
     * select("字段名 AS 字段名别名")  => 表别名.字段名 AS '字段名别名'
     * select("字段名 AS '字段名别名'")  => 表别名.字段名 AS '字段名别名'
     *
     * @param tableClazz   字段所属的表 == 内部会自动为每个字段名加表别名
     * @param dbFieldNames 字段名
     *                     如    name => 表chaiji_status => cs_8d053.account
     * @return
     */
    QueryWrapper<FirstTable> select(Class tableClazz, String... dbFieldNames);

    /**
     * 左连
     * 【FirstTable】主表左连【secondTableClazz】表
     *
     * @param secondTableClazz 此表与主表进行左连
     * @return
     */
    <SecondTable> OnWrapperImpl<FirstTable, FirstTable, SecondTable> leftJoin(Class<SecondTable> secondTableClazz);

    /**
     * 左连
     * 【FirstTable】主表左连【secondTableClazz】表
     *
     * @param secondTableClazz 此表与主表进行左连
     * @param joinOnSqlAppendFlag 是否将on后面的判断信息连到已有的join上
     * @return
     */
    <SecondTable> OnWrapperImpl<FirstTable, FirstTable, SecondTable> leftJoin(Class<SecondTable> secondTableClazz, boolean joinOnSqlAppendFlag);

    /**
     * 左连
     * 【leftableClazz】表左连【secondTableClazz】表
     *
     * @param leftableClazz 左表
     * @param secondTableClazz 右表
     * @return
     */
    <T, SecondTable> OnWrapperImpl<FirstTable, T, SecondTable> leftJoin(Class<T> leftableClazz, Class<SecondTable> secondTableClazz);

    /**
     * 左连
     * 【leftableClazz】表左连【secondTableClazz】表
     * <p>
     * 注意：必须确保此表【leftableClazz】在前面拼好的SQL能找到，否则报错
     *
     * @param leftableClazz 左表
     * @param secondTableClazz 右表
     * @param joinOnSqlAppendFlag 是否将on后面的判断信息连到已有的join上
     * @return
     */
    <T, SecondTable> OnWrapperImpl<FirstTable, T, SecondTable> leftJoin(Class<T> leftableClazz, Class<SecondTable> secondTableClazz, boolean joinOnSqlAppendFlag);

    /**
     * 等值连
     * 【FirstTable】主表等值连【secondTableClazz】表
     *
     * @param secondTableClazz 此表与主表进行左连
     * @param <SecondTable>
     * @return
     */
    <SecondTable> OnWrapperImpl<FirstTable, FirstTable, SecondTable> innerJoin(Class<SecondTable> secondTableClazz);

    /**
     * 等值连
     * 【FirstTable】主表等值连【secondTableClazz】表
     *
     * @param secondTableClazz 此表与主表进行左连
     * @param joinOnSqlAppendFlag 是否将on后面的判断信息连到已有的join上
     * @return
     */
    <SecondTable> OnWrapperImpl<FirstTable, FirstTable, SecondTable> innerJoin(Class<SecondTable> secondTableClazz, boolean joinOnSqlAppendFlag);

    /**
     * 等值连
     * @param leftableClazz 左表
     * @param secondTableClazz 右表
     * @return
     */
    <T, SecondTable> OnWrapperImpl<FirstTable, T, SecondTable> innerJoin(Class<T> leftableClazz, Class<SecondTable> secondTableClazz);

    /**
     * 等值连
     * 【leftableClazz】表等值连【secondTableClazz】表
     * <p>
     * 注意：必须确保此表【leftableClazz】在前面拼好的SQL能找到，否则报错
     *
     * @param leftableClazz 左表
     * @param secondTableClazz 右表
     * @param joinOnSqlAppendFlag 是否将on后面的判断信息连到已有的join上
     * @return
     */
    <T, SecondTable> OnWrapperImpl<FirstTable, T, SecondTable> innerJoin(Class<T> leftableClazz, Class<SecondTable> secondTableClazz, boolean joinOnSqlAppendFlag);

    /**
     * 右连
     * 【FirstTable】主表右连【secondTableClazz】表
     *
     * @param secondTableClazz 此表与主表进行右连
     * @return
     */
    <SecondTable> OnWrapperImpl<FirstTable, FirstTable, SecondTable> rightJoin(Class<SecondTable> secondTableClazz);

    /**
     * 右连
     * 【FirstTable】主表右连【secondTableClazz】表
     *
     * @param secondTableClazz 此表与主表进行右连
     * @param joinOnSqlAppendFlag 是否将on后面的判断信息连到已有的join上
     * @return
     */
    <SecondTable> OnWrapperImpl<FirstTable, FirstTable, SecondTable> rightJoin(Class<SecondTable> secondTableClazz, boolean joinOnSqlAppendFlag);

    /**
     * 右连
     * @param leftableClazz 左表
     * @param secondTableClazz 右表
     * @return
     */
    <T, SecondTable> OnWrapperImpl<FirstTable, T, SecondTable> rightJoin(Class<T> leftableClazz, Class<SecondTable> secondTableClazz);

    /**
     * 右连
     * 【leftableClazz】表右连【secondTableClazz】表
     * 注意：必须确保此表【leftableClazz】在前面拼好的SQL能找到，否则报错
     *
     * @param leftableClazz 左表
     * @param secondTableClazz 右表
     * @param joinOnSqlAppendFlag 是否将on后面的判断信息连到已有的join上
     * @return
     */
    <T, SecondTable> OnWrapperImpl<FirstTable, T, SecondTable> rightJoin(Class<T> leftableClazz, Class<SecondTable> secondTableClazz, boolean joinOnSqlAppendFlag);

    /**
     * 分组
     *
     * @param groupFieldNames 属于主表的字段
     * @return
     */
    QueryWrapper<FirstTable> groupBy(String... groupFieldNames);

    /**
     * 分组
     *
     * @param tableClazz      {groupFieldNames}所属的表字段
     * @param groupFieldNames
     * @return
     */
    QueryWrapper<FirstTable> groupBy(Class tableClazz, String... groupFieldNames);

    /**
     * 有having筛选条件则使用这个
     *
     * @param groupFieldNames 待分组的主表字段
     * @return
     */
    HavingWrapperImpl<FirstTable, FirstTable, QueryWrapper<FirstTable>> groupByHaving(String... groupFieldNames);

    /**
     * 有having筛选条件则使用这个
     *
     * @param groupFieldNames 待分组的字段
     * @return
     */
    <SecondTable> HavingWrapperImpl<FirstTable, SecondTable, QueryWrapper<FirstTable>> groupByHaving(Class<SecondTable> tableClazz, String... groupFieldNames);

    /**
     * 升序
     *
     * @param orderByFieldNames 待分组的主表字段
     * @return
     */
    QueryWrapper<FirstTable> asc(String... orderByFieldNames);

    /**
     * 升序
     *
     * @param tableClazz        {orderByFieldNames}字段所属表
     * @param orderByFieldNames
     * @return
     */
    QueryWrapper<FirstTable> asc(Class tableClazz, String... orderByFieldNames);

    /**
     * 倒序
     *
     * @param orderByFieldNames 待分组的主表字段
     * @return
     */
    QueryWrapper<FirstTable> desc(String... orderByFieldNames);

    /**
     * 倒序
     *
     * @param tableClazz        {orderByFieldNames}字段所属表
     * @param orderByFieldNames
     * @return
     */
    QueryWrapper<FirstTable> desc(Class tableClazz, String... orderByFieldNames);

    /**
     * 取消分页
     *
     * @return
     */
    QueryWrapper<FirstTable> notPage();

    /**
     * 分页
     *
     * @param pageNum 第N页 从1开始
     * @param pageNum 每页显示的条数
     * @return
     */
    QueryWrapper<FirstTable> page(long pageNum, long pageSize);

    /**
     * 分页
     *
     * @param startIndex 从第N（启始从0开始）条记录开始查找（包括第N条）
     * @param pageSize   每页最多的记录数
     * @return
     */
    QueryWrapper<FirstTable> limit(long startIndex, long pageSize);
}
